package com.manager.commons.utils;

//                   _ooOoo_    
//                  o8888888o    
//                  88" . "88    
//                  (| -_- |)    
//                   O\ = /O    
//               ____/'---'\____    
//              /. '\\| : |//' .\    
//             // \\||| : |||// \\   
//            // _|||||-:-|||||_ \\    
//           // | | \\\ - /// | | \\
//           || |_| ''\---/'' |_| || 
//            \ .-\___/'-'\___/-. /    
//          ___\. .' /--.--\ '. ./___    
//        .""'< `.___\_<|>_/___.' >'"".    
//       | |: `- \`.|'\ _ /'|.`/ -` :| |    
//        \ \ `-. \_ __\ /__ _/ .-` / /    
//======'-.___`-.___\_______/___.-`___.-'======    
//                   '=---='    
//.................................................    
//写一哈代码，你就青叫唤；信龟儿设计，你逗是傻逼。
//永无Bug，啷个可能！求佛主保佑也没球用！

/**
 * CoordinateUtils(坐标)
 * @author H
 * @version V1.0
 */
public class CoordinateUtils {

	private static final double X_PI = 3.14159265358979324 * 3000.0 / 180.0;
	private static final double PI = 3.14159265358979324;
	// 卫星椭球坐标投影到平面地图坐标系的投影因子。 地球长半径
	private static final double EARTH_MAJOR_RADIUS = 6378245.0;
	// 椭球的偏心率。
	private static final double ECCENTRICITY_RATIO = 0.00669342162296594323;

	/**
	 * 百度坐标(bd09II)转火星坐标(GCJ02)
	 * @Param longitude 百度坐标经度
	 * @Param latitude 百度坐标纬度
	 */
	public static Double[] baiduToMars(double longitude, double latitude) {
		double x = longitude - 0.0065, y = latitude - 0.006;
		double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI);
		double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI);
		double lon = z * Math.cos(theta);
		double lat = z * Math.sin(theta);
		return new Double[] { lon, lat };
	}

	/**
	 * 火星坐标系(GCJ02)转百度坐标系(bd09II)
	 * @Param longitude 火星坐标经度
	 * @Param latitude 火星坐标纬度
	 */
	public static Double[] marsToBaidu(double longitude, double latitude) {
		double x = longitude, y = latitude;
		double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * X_PI);
		double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * X_PI);

		double lon = z * Math.cos(theta) + 0.0065;
		double lat = z * Math.sin(theta) + 0.006;
		return new Double[] { lon, lat };
	}

	/**
	 * 火星坐标系(GCJ02)转地球坐标系(WGS84)
	 * @Param longitude 火星坐标经度
	 * @Param latitude 火星坐标纬度
	 */
	public static Double[] gcj2ToWGS(double longitude, double latitude) {
		Double[] location = delta(longitude, latitude);
		double lon = longitude - location[0];
		double lat = latitude - location[1];
		return new Double[] { lon, lat };
	}

	/**
	 * 判断是否在国内，不在国内则不做偏移
	 * @param longitude
	 * @param latitude
	 * @return
	 */
	private static boolean outOfChina(double longitude, double latitude) {
        return (longitude < 72.004 || longitude > 137.8347) && (latitude < 0.8293 || latitude > 55.8271);
	}

	/**
	 * 三角洲
	 * @param longitude
	 * @param latitude
	 * @return
	 */
	private static Double[] delta(double longitude, double latitude) {
		double dLongitude = transform(longitude - 105.0, latitude - 35.0, PI, 0);
		double dLatitude = transform(longitude - 105.0, latitude - 35.0, PI, 1);
		double radLat = latitude / 180.0 * PI;
		double magic = Math.sin(radLat);
		magic = 1 - ECCENTRICITY_RATIO * magic * magic;
		double sqrtMagic = Math.sqrt(magic);
		dLatitude = (dLatitude * 180.0) / ((EARTH_MAJOR_RADIUS * (1 - ECCENTRICITY_RATIO)) / (magic * sqrtMagic) * PI);
		dLongitude = (dLongitude * 180.0) / (EARTH_MAJOR_RADIUS / sqrtMagic * Math.cos(radLat) * PI);

		double lon = longitude + dLongitude;
		double lat = latitude + dLatitude;
		return new Double[] { lon, lat };
	}

	/**
	 * 地球坐标系(WGS-84)转火星坐标系(GCJ)
	 * @Param longitude 地球坐标经度
	 * @Param latitude 地球坐标纬度
	 */
	public static Double[] transform(double longitude, double latitude) {
		// 如果是国外坐标点，则直接返回传进来的坐标点
		if (outOfChina(longitude, latitude)) {
			return new Double[] { longitude, latitude };
		}
		return delta(longitude, latitude);
	}

	/**
	 * 转换
	 * @param x
	 * @param y
	 * @param pi
	 * @param way
	 * @return
	 */
	private static double transform(double x, double y, double pi, int way) {
		if (0 == way) {
			double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
			ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
			ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
			ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
			return ret;
		} else if (1 == way) {
			double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
			ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
			ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
			ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
			return ret;
		}
		return 0L;
	}
}